﻿using System;
using System.IO;
using System.Xml;

using StaticPublic.iTunesParser.Music;

namespace StaticPublic.iTunesParser {
    public class LibraryParser {
        public LibraryParser(ParserOptions options) {
            Options = options;
        }


        #region Properties

        public ParserOptions Options { get; private set; }

        public MusicLibrary Library { get; private set; }

        static private XmlReaderSettings ReaderSettings {
            get {
                return new XmlReaderSettings { 
                    IgnoreWhitespace = true,
                    ProhibitDtd = false 
                };
            }
        }

        private XmlReader Reader { get; set; }

        #endregion


        public void Run() {
            LoadLibrary();

            new LibraryWriter(Library).WriteHtml(Options.OutputPath);
        }

        private void LoadLibrary() {
            Library = new MusicLibrary();

            using (Stream stream = File.OpenRead(Options.InputPath)) {
                using (Reader = XmlReader.Create(stream, ReaderSettings)) {
                    MoveToTracks();

                    while (Reader.Read()) {
                        if (!(Reader.NodeType == XmlNodeType.Element && String.Equals(Reader.Name, "dict"))) {
                            continue;
                        }

                        Library.AddTrack(Reader.ReadSubtree());
                    }
                }
            }

            Console.WriteLine("Loaded {0} albums", Library.Albums.Count);
        }

        /// <summary>
        /// Moves the reader to the dictionary of tracks. This is found at: plist/dict/dict
        /// </summary>
        private void MoveToTracks() {
            MoveTo("plist");
            MoveTo("dict");
            MoveTo("dict");
        }

        /// <summary>
        /// Moves the reader to the nominated node. If the node was not found, an exception is thrown.
        /// </summary>
        /// <param name="node">Name of the node to move to</param>
        private void MoveTo(string node) {
            if (!Reader.ReadToDescendant(node)) {
                throw new ParserException("Could not read to descendent: {0}", node);
            }
        }
    }
}
